
open Operator_ast
open Namespace_ast_fullfill
open Namespace_ast_absolute
open Tools_identifier

module StrSet = Set.Make(String)
module StrMap = Map.Make(String)

type context = {
	cop_idents : string StrMap.t;
	cop_namespace : fullfill;
	cop_absolute : StrSet.t;
	cop_in_namespace : bool
}

let transform ast =

	let rec transform_list func (data:context) = function
		| [] -> data, []
		| a::lst -> let data,a = func (data:context) a in
			let data,lst = transform_list func (data:context) lst in
			data,(a::lst) in

	let rec transform_program ast = 
		let fullfill = fullfill_list fullfill_sourceElement {
			idents = StrSet.empty;
			namespaces = StrMap.empty;
			locals = StrSet.empty;
		} ast in
		let absolute = absolute_list absolute_sourceElement {
			abs_idents = StrSet.empty
		} StrSet.empty ast in
		
		let context = {
			cop_idents = StrMap.empty;
			cop_namespace = fullfill;
			cop_absolute = absolute.abs_idents;
			cop_in_namespace = false
		} in
		let _, ast = transform_list transform_sourceElement context ast in
		
		StrMap.fold (fun ident namespace ast -> 
			(AStatement (
			AVariableStatement (true, false, [
				(ident, Some (create_namespaceExpression namespace))])))::ast
			) fullfill.namespaces ast
	
	and create_namespaceExpression namespace =
		let lst = StrMap.fold (fun k v lst -> (APropAssignment(AIdentifierName k, create_namespaceExpression v))::lst) namespace.namespaces [] in
		let lst = StrSet.fold (fun v lst -> if StrMap.mem v namespace.namespaces then lst else (APropAssignment(AIdentifierName v, 
			ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(
					ANewExpression(AMemberExpression(APrimaryExpr(AIdentifier "undefined"))))))))
			))::lst) namespace.idents lst in
		ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(ANewExpression(
				AMemberExpression(APrimaryExpr(AObjectLiteral lst))))))))
	
	and transform_sourceElement (data:context) = function
		| Namespace_ast.AStatement stmt -> 
			let data, stmt = transform_statement (data:context) stmt in
			data, (AStatement stmt)
		| Namespace_ast.ANamespace stmt ->
			let data, stmt = transform_namespace (data:context) stmt in
			data, (AStatement stmt)
		(*| Namespace_ast.AFunctionDeclaration funcDecl ->  
			let data= funcDecl = transform_functionDeclaration (data:context) funcDecl in
			data, (AFunctionDeclaration funcDecl) *) (* Modif #1 *)
	
	
	and transform_functionDeclaration (data:context) (is_private,is_meta,is_inline,ident,params,body) = 
		let data, params, body = transform_functionContent (data:context) params body in
		if data.cop_in_namespace && not is_private then
			data, (AExpressionStatement [(AAssignOp(
					ANewExpression(AMemberExpression(AMemberDotExpr(APrimaryExpr(AThis),ident))),
					"=", ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(
					ANewExpression(AMemberExpression(AFunctionExpr (is_inline,Some ident,params,body)))
				)))))))])
		else
			data, (AFuncDeclaration(is_private, is_meta, is_inline, ident, params, body))
	
	and transform_functionDeclaration2 (data:context) (is_private, is_meta, is_inline,ident,params,body) = 
		let data, params, body = transform_functionContent (data:context) params body in
			data, (is_private, is_meta, is_inline, ident, params, body)
		
	and transform_functionExpression (data:context) (is_inline, ident, params, body) =
		let data, params, body = transform_functionContent (data:context) params body in
		data, (is_inline, ident, params, body)
	
	and transform_functionContent (data:context) params body =
	
		let fullfill = fullfill_list fullfill_sourceElement {
			idents = StrSet.empty;
			namespaces = StrMap.empty;
			locals = List.fold_right (fun i set -> StrSet.add i set ) params StrSet.empty;
		} body in
	
		let data2 = {
			cop_idents = StrMap.fold (fun k v map -> 
				if (StrSet.mem k fullfill.locals 
					|| StrSet.mem k fullfill.idents) 
				then map else StrMap.add k v map) data.cop_idents StrMap.empty;
			cop_namespace = data.cop_namespace;
			cop_absolute = data.cop_absolute;
			cop_in_namespace = false
		} in
		
		let data2, body = transform_functionBody (data2:context) body in
		let data = {
			cop_idents = data.cop_idents;
			cop_namespace = data.cop_namespace;
			cop_absolute = data2.cop_absolute;
			cop_in_namespace = data.cop_in_namespace
		} in
		data, params, body
		
	and transform_functionBody (data:context) body = 
		transform_list transform_sourceElement (data:context) body

	(* Statements *)
	and transform_block (data:context) stmts =
		transform_list transform_statement (data:context) stmts

	and transform_statement (data:context) = function
		| Namespace_ast.ABlock block -> 
			let data, block = transform_block (data:context) block in
			data, (ABlock block)
		| Namespace_ast.AOperatorAssignment stmt -> 
			let data, stmt = transform_operatorAssignment data stmt in
			data, AOperatorAssignment stmt
		| Namespace_ast.AOperatorUnassignment stmt -> 
			data, (AOperatorUnassignment stmt)
		| Namespace_ast.AVariableStatement vs -> 
			let data, vs = transform_variableStatement (data:context) vs in
			data, vs
		| Namespace_ast.AConstStatement cs -> 
			let data, cs = transform_constStatement (data:context) cs in
			data, cs
		| Namespace_ast.AFuncDeclaration fd -> 
			let data, fd = transform_functionDeclaration (data:context) fd in
			data, fd	(* Modif #1 *)
		| Namespace_ast.AClassStatement cs -> 
			let data, cs = transform_classStatement (data:context) cs in
			data, (AClassStatement cs)
		| Namespace_ast.AEmptyStatement -> data, AEmptyStatement
		| Namespace_ast.AExpressionStatement expr -> 
			let data, expr = transform_expression (data:context) expr in
			data, (AExpressionStatement expr)
		| Namespace_ast.AIfStatement stmt -> 
			let data, stmt = transform_ifStatement (data:context) stmt in
			data, (AIfStatement stmt)
		| Namespace_ast.AIterationStatement stmt -> 
			let data, stmt = transform_iterationStatement (data:context) stmt in
			data, (AIterationStatement stmt)
		| Namespace_ast.AContinueStatement e -> data, AContinueStatement e
		| Namespace_ast.ABreakStatement e -> data, ABreakStatement e
		| Namespace_ast.AReturnStatement expr -> 
			let data, expr = transform_optionalExpression (data:context) expr in
			data, (AReturnStatement expr)
		| Namespace_ast.AWithStatement stmt -> 
			let data, stmt = transform_withStatement (data:context) stmt in
			data, (AWithStatement stmt)
		| Namespace_ast.ALabelledStatement stmt -> 
			let data, stmt = transform_labelledStatement (data:context) stmt in
			data, (ALabelledStatement stmt)
		| Namespace_ast.ASwitchStatement stmt -> 
			let data, stmt = transform_switchStatement (data:context) stmt in
			data, (ASwitchStatement stmt)
		| Namespace_ast.AThrowStatement expr -> 
			let data, expr = transform_expression (data:context) expr in
			data, (AThrowStatement expr)
		| Namespace_ast.ATryStatement stmt -> 
			let data, stmt = transform_tryStatement (data:context) stmt in
			data, (ATryStatement stmt)
		| Namespace_ast.ADebuggerStatement -> data, ADebuggerStatement
	
	and transform_namespace data (idents, body) =
	
		let cop_idents,cop_namespace,cop_absolute,lst,_ = List.fold_right (fun i (cop_idents,cop_namespace,cop_absolute,lst,ident) ->
			let map, _, _ = free_ident (StrMap.empty,StrSet.empty,cop_absolute) "?" false in
			let newIdent = StrMap.find "?" map in
			let cop_absolute = StrSet.add newIdent cop_absolute in
			let cop_namespace = StrMap.find i cop_namespace.namespaces in
			let cop_idents = StrSet.fold (fun j cop_idents -> StrMap.add j newIdent cop_idents) cop_namespace.idents cop_idents in
			let expr = match ident with
				| None -> if StrMap.mem i data.cop_idents then AMemberDotExpr ((APrimaryExpr (AIdentifier (StrMap.find i data.cop_idents))), i) else APrimaryExpr (AIdentifier i)
				| Some ident -> AMemberDotExpr ((APrimaryExpr (AIdentifier ident)), i) in
			let lst = (newIdent,Some (ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(
					ANewExpression(AMemberExpression(expr)))))))))::lst in
			(cop_idents, cop_namespace, cop_absolute,lst,Some newIdent)
			) (List.rev idents) (data.cop_idents,data.cop_namespace,data.cop_absolute,[],None) in


		let fullfill = fullfill_list fullfill_sourceElement {
			idents = StrSet.empty;
			namespaces = StrMap.empty;
			locals = StrSet.empty;
		} body in

		let data2 = {
			cop_idents = StrMap.fold (fun k v map -> 
				if StrSet.mem k fullfill.locals
				then map else StrMap.add k v map) cop_idents StrMap.empty;
			cop_namespace = cop_namespace;
			cop_absolute = cop_absolute;
			cop_in_namespace = true
		} in
	
		let data2, body = transform_functionBody data2 body in
		let data = {
			cop_idents = data.cop_idents;
			cop_namespace = data.cop_namespace;
			cop_absolute = data2.cop_absolute;
			cop_in_namespace = data.cop_in_namespace
		} in
		let body = AStatement(AVariableStatement(true,false,List.rev lst))::body in
		data, AExpressionStatement [
			ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(ACallExpression(
				ACallMemberArgs((
					AMemberDotExpr(
					(APrimaryExpr (AExpression [
						ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(
						ANewExpression(AMemberExpression(AFunctionExpr (true,None,[],body))))))))
					])), "call"
					)
				), 
				[ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(
				ANewExpression(AMemberExpression(create_astFromIdents (List.rev idents))))))))]
				)))))))
		]
	
	and create_astFromIdents = function
		| [] -> APrimaryExpr (AThis)
		| a::lst -> AMemberDotExpr ((create_astFromIdents lst), a)
	
	and transform_operatorAssignment (data:context) (op,expr) =
		let data, expr = transform_assignmentExpression data expr in
		data, (op, expr)

	and transform_variableStatement (data:context) (is_private, is_meta, varDecls) =
		if data.cop_in_namespace && not is_private then
			let data, varDecls = transform_list transform_variableDeclarationToExpr data varDecls in
			data, AExpressionStatement (varDecls)
		else
			let data, varDecls = transform_list transform_variableDeclaration (data:context) varDecls in
			data, AVariableStatement (is_private, is_meta, varDecls)
	
	and transform_variableStatement2 (data:context) (is_private, is_meta, varDecls) =
		let data, varDecls = transform_list transform_variableDeclaration (data:context) varDecls in
		data, (is_private, is_meta, varDecls)
	
	and transform_constStatement2 (data:context) (is_private, is_meta, varDecls) =
		let data, varDecls = transform_list transform_variableDeclaration (data:context) varDecls in
		data, (is_private, is_meta, varDecls)
		
	and transform_classStatement (data:context) (is_private, is_meta, ident, extends, classElements) =
		let data, classElements = transform_list transform_classElement (data:context) classElements in
		data, (is_private, is_meta, ident, extends, classElements)

	and transform_classElement (data:context) m = 
		let data2 = {
			cop_idents = data.cop_idents;
			cop_namespace = data.cop_namespace;
			cop_absolute = data.cop_absolute;
			cop_in_namespace = false;
		} in
		let data2, v = (match m with 
		| Namespace_ast.ACVariableStatement v -> 
			let data, v = transform_variableStatement2 data2 v in
			data, (ACVariableStatement v)
		| Namespace_ast.ACConstStatement c -> 
			let data, c = transform_constStatement2 data2 c in
			data, (ACConstStatement c)
		| Namespace_ast.ACFuncDeclaration funcDecl -> 
			let data, funcDecl = transform_functionDeclaration2 data2 funcDecl in
			data, (ACFuncDeclaration funcDecl)) in
		let data = {
			cop_idents = data.cop_idents;
			cop_namespace = data.cop_namespace;
			cop_absolute = data2.cop_absolute;
			cop_in_namespace = data.cop_in_namespace
		} in
		data, v

	and transform_constStatement (data:context) (is_private, is_meta, varDecls) =
		if data.cop_in_namespace && not is_private then
			let data, varDecls = transform_list transform_variableDeclarationToExpr data varDecls in
			data, AExpressionStatement (varDecls)
		else
		let data, varDecls = transform_list transform_variableDeclaration (data:context) varDecls in
		data, AConstStatement(is_private, is_meta, varDecls)

	and transform_variableDeclaration (data:context) (ident, init) =
		(match init with
			| None -> data, (ident, None)
			| Some expr -> 
				let data, expr = transform_assignmentExpression (data:context) expr in
				data, (ident, (Some expr)))
	
	and transform_variableDeclarationToExpr (data:context) (ident, init) =
		(match init with
			| None -> data, (ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(ANewExpression(
				AMemberExpression(APrimaryExpr(AIdentifier ident)))))))))
			| Some expr -> 
				let data, expr = transform_assignmentExpression (data:context) expr in
				data, (AAssignOp(
					ANewExpression(AMemberExpression(AMemberDotExpr(APrimaryExpr(AThis),ident))),
					"=", expr
				)))

	and transform_ifStatement (data:context) = function
		| Namespace_ast.AIfElse (expr, stmt1, stmt2) -> 
			let data, expr = transform_expression (data:context) expr in
			let data, stmt1 = transform_statement (data:context) stmt1 in
			let data, stmt2 = transform_statement (data:context) stmt2 in
			data, (AIfElse (expr, stmt1, stmt2))
		| Namespace_ast.AIf (expr, stmt) -> 
			let data, expr = transform_expression (data:context) expr in
			let data, stmt = transform_statement (data:context) stmt in
			data, (AIf (expr, stmt))

	and transform_iterationStatement (data:context) = function
		| Namespace_ast.ADoWhile (stmt, expr) ->
			let data, stmt = transform_statement (data:context) stmt in
			let data, expr = transform_expression (data:context) expr in
			data, (ADoWhile (stmt, expr))
		| Namespace_ast.AWhile (expr, stmt) -> 
			let data, expr = transform_expression (data:context) expr in
			let data, stmt = transform_statement (data:context) stmt in
			data, (AWhile (expr, stmt))
		| Namespace_ast.AFor (expr1, expr2, expr3, stmt) ->
			let data, expr1 = transform_optionalExpression (data:context) expr1 in
			let data, expr2 = transform_optionalExpression (data:context) expr2 in
			let data, expr3 = transform_optionalExpression (data:context) expr3 in
			let data, stmt = transform_statement (data:context) stmt in
			data, (AFor (expr1, expr2, expr3, stmt ))
		| Namespace_ast.AForVar (is_meta, varDecls, expr1, expr2, stmt) ->
			let data, varDecls = transform_list transform_variableDeclaration (data:context) varDecls in
			let data, expr1 = transform_optionalExpression data expr1 in
			let data, expr2 = transform_optionalExpression data expr2 in
			let data, stmt = transform_statement data stmt in
			data, (AForVar (is_meta, varDecls, expr1, expr2, stmt))
		| Namespace_ast.AForIn (lhs, expr, stmt) ->
			let data, lhs = transform_leftHandSideExpression (data:context) lhs in
			let data, expr = transform_expression (data:context) expr in
			let data, stmt = transform_statement (data:context) stmt in
			data, (AForIn (lhs, expr, stmt))
		| Namespace_ast.AForVarIn (is_meta, varDecl, expr, stmt) ->
			let data, varDecl = transform_variableDeclaration (data:context) varDecl in
			let data, expr = transform_expression (data:context) expr in
			let data, stmt = transform_statement (data:context) stmt in
			data, (AForVarIn (is_meta, varDecl, expr, stmt))

	and transform_optionalExpression (data:context) = function
		| None -> data, None
		| Some expr -> let data, expr = transform_expression (data:context) expr in
			data, (Some expr)

	and transform_withStatement (data:context) (expr, stmt) =
		let data, expr = transform_expression (data:context) expr in
		let data, stmt = transform_statement (data:context) stmt in
		data, (expr,stmt)
		
	and transform_switchStatement (data:context) (expr, caseBlock) =
		let data, expr = transform_expression (data:context) expr in
		let data, caseBlock = transform_caseBlock (data:context) caseBlock in
		data, (expr,caseBlock)

	and transform_caseBlock (data:context) = function
		| Namespace_ast.ACasesNoDefault caseClauses -> 
			let data, caseClauses = transform_list transform_caseClause (data:context) caseClauses in
			data, (ACasesNoDefault caseClauses)
		| Namespace_ast.ACasesDefault (caseClauses1, defaultClause, caseClauses2) ->
			let data, caseClauses1 = transform_list transform_caseClause (data:context) caseClauses1 in
			let data, defaultClause = transform_list transform_statement (data:context) defaultClause in
			let data, caseClauses2 = transform_list transform_caseClause (data:context) caseClauses2 in
			data, (ACasesDefault (caseClauses1, defaultClause, caseClauses2))

	and transform_caseClause (data:context) (expr, stmts) = 
		let data, expr = transform_expression (data:context) expr in
		let data, stmts = transform_list transform_statement (data:context) stmts in
		data, (expr, stmts)

	and transform_labelledStatement (data:context) (ident, stmt) =
		let data, stmt = transform_statement (data:context) stmt in
		data, (ident, stmt)

	and transform_tryStatement (data:context) = function
		| Namespace_ast.ATryCatch (block, catch) ->
			let data, block = transform_block (data:context) block in
			let data, catch = transform_catch (data:context) catch in
			data, (ATryCatch (block, catch))
		| Namespace_ast.ATryFinally (block, finally) ->
			let data, block = transform_block (data:context) block in
			let data, finally = transform_block (data:context) finally in
			data, (ATryFinally (block, finally))
		| Namespace_ast.ATryCatchFinally (block, catch, finally) ->
			let data, block = transform_block (data:context) block in
			let data, catch = transform_catch (data:context) catch in
			let data, finally = transform_block (data:context) finally in
			data, (ATryCatchFinally (block, catch, finally))
			
	and transform_catch (data:context) (ident, block) =
		let data, block = transform_block (data:context) block in
		data, (ident, block)

	(* Literals *)
	and transform_literal = function
		| Namespace_ast.ANull -> ANull
		| Namespace_ast.ABooleanLiteral b -> ABooleanLiteral b
		| Namespace_ast.ALitNumericLiteral s -> ALitNumericLiteral s
		| Namespace_ast.ALitStringLiteral s -> ALitStringLiteral s
		| Namespace_ast.ARegularExpressionLiteral regex -> ARegularExpressionLiteral regex

	(* Expressions *)
	and transform_primaryExpression (data:context) = function
		| Namespace_ast.AThis -> data, AThis
		| Namespace_ast.AIdentifier ident -> 
			if StrMap.mem ident data.cop_idents then
			data, (AExpression [
				ACondExpr(ACondBinaryExpr(AUnaryExpr(APostfixExpr(ALeftHandSide(ANewExpression(
				AMemberExpression(
					AMemberDotExpr (
						APrimaryExpr (AIdentifier (StrMap.find ident data.cop_idents)),
						ident
					))))))))])
			else
			data, (AIdentifier ident)
		| Namespace_ast.ALiteral literal -> data, ALiteral (transform_literal literal)
		| Namespace_ast.AArrayLiteral literal -> 
			let data, literal = transform_arrayLiteral (data:context) literal in
			data, (AArrayLiteral literal)
		| Namespace_ast.AObjectLiteral literal -> 
			let data, literal = transform_objectLiteral (data:context) literal in
			data, (AObjectLiteral literal)
		| Namespace_ast.AExpression expr -> 
			let data, expr = transform_expression (data:context) expr in
			data, (AExpression expr)

	and transform_arrayLiteral (data:context) = function
		| Namespace_ast.AElisions elisions -> data, (AElisions (List.map transform_elision elisions))
		| Namespace_ast.AElements elements -> 
			let data, elements = transform_list transform_element (data:context) elements in
			data, (AElements elements)
		| Namespace_ast.AElementsAndElisions (elements, elisions) ->
			let data, elements = transform_list transform_element (data:context) elements in
			let elisions = List.map transform_elision elisions in
			data, (AElementsAndElisions (elements, elisions))

	and transform_elision _ = AElision

	and transform_element (data:context) (elisions, expr) = 
		let elisions = List.map transform_elision elisions in
		let data, expr = transform_assignmentExpression data expr in
		data, (elisions,expr)

	and transform_objectLiteral (data:context) props = 
		transform_list transform_propertyAssignment (data:context) props

	and transform_propertyAssignment (data:context) = function
		| Namespace_ast.APropAssignment (prop,expr) -> 
			let prop = transform_propertyName prop in
			let data, expr = transform_assignmentExpression (data:context) expr in
			data, (APropAssignment (prop, expr))
		| Namespace_ast.APropGet (prop, body) ->
			let prop = transform_propertyName prop in
			let data, _, body = transform_functionContent (data:context) [] body in
			data, (APropGet (prop, body))
		| Namespace_ast.APropSet (prop, params, body) ->
			let prop = transform_propertyName prop in
			let data, params, body = transform_functionContent (data:context) params body in
			data, (APropSet (prop, params, body))

	and transform_propertyName = function
		| Namespace_ast.AIdentifierName s -> AIdentifierName s
		| Namespace_ast.AStringLiteral s -> AStringLiteral s
		| Namespace_ast.ANumericLiteral s -> ANumericLiteral s

	and transform_memberExpression (data:context) = function
		| Namespace_ast.APrimaryExpr expr -> 
			let data, expr = transform_primaryExpression (data:context) expr in
			data, (APrimaryExpr expr)
		| Namespace_ast.AFunctionExpr expr -> 
			let data, expr = transform_functionExpression (data:context) expr in
			data, (AFunctionExpr expr)
		| Namespace_ast.AMemberBracketExpr (expr1, expr2) -> 
			let data, expr1 = transform_memberExpression (data:context) expr1 in
			let data, expr2 = transform_expression (data:context) expr2 in
			data, (AMemberBracketExpr (expr1, expr2))
		| Namespace_ast.AMemberDotExpr (expr, ident) ->
			let data, expr = transform_memberExpression (data:context) expr in
			data, (AMemberDotExpr (expr, ident))
		| Namespace_ast.AMemberNewExpr (expr, args) ->
			let data, expr = transform_memberExpression (data:context) expr in
			let data, args = transform_arguments (data:context) args in
			data, (AMemberNewExpr (expr, args))

	and transform_newExpression (data:context) = function
		| Namespace_ast.AMemberExpression expr ->
			let data, expr = transform_memberExpression (data:context) expr in
			data, (AMemberExpression expr)
		| Namespace_ast.ANewMemberExpression expr ->
			let data, expr = transform_newExpression (data:context) expr in
			data, (ANewMemberExpression expr)

	and transform_callExpression (data:context) = function
		| Namespace_ast.ACallMemberArgs (expr,args) ->
			let data, expr = transform_memberExpression (data:context) expr in
			let data, args = transform_arguments (data:context) args in
			data, (ACallMemberArgs (expr, args))
		| Namespace_ast.ACallExpressionArgs (expr, args) ->
			let data, expr = transform_callExpression (data:context) expr in
			let data, args = transform_arguments (data:context) args in
			data, (ACallExpressionArgs (expr, args))
		| Namespace_ast.ACallExpressionExpr (expr1, expr2) ->
			let data, expr1 = transform_callExpression (data:context) expr1 in
			let data, expr2 = transform_expression (data:context) expr2 in
			data, (ACallExpressionExpr (expr1, expr2))
		| Namespace_ast.ACallExpressionIdent (expr, ident) ->
			let data, expr = transform_callExpression (data:context) expr in
			data, (ACallExpressionIdent (expr, ident))

	and transform_arguments (data:context) args = 
		transform_list transform_assignmentExpression (data:context) args

	and transform_leftHandSideExpression (data:context) = function
		| Namespace_ast.ANewExpression expr ->
			let data, expr = transform_newExpression (data:context) expr in
			data, (ANewExpression expr)
		| Namespace_ast.ACallExpression expr ->
			let data, expr = transform_callExpression (data:context) expr in
			data, (ACallExpression expr)

	and transform_postfixExpression (data:context) = function
		| Namespace_ast.ALeftHandSide lhs ->
			let data, lhs = transform_leftHandSideExpression (data:context) lhs in
			data, (ALeftHandSide lhs)
		| Namespace_ast.ALeftHandSideOp (lhs,op) ->
			let data, lhs = transform_leftHandSideExpression (data:context) lhs in
			data, ALeftHandSideOp (lhs,op)

	and transform_unaryExpression (data:context) = function
		| Namespace_ast.APostfixExpr expr ->
			let data, expr = transform_postfixExpression (data:context) expr in
			data, (APostfixExpr expr)
		| Namespace_ast.AOpUnaryExpr (op,expr) ->
			let data, expr = transform_unaryExpression (data:context) expr in
			data, (AOpUnaryExpr (op, expr))

	and transform_binaryExpression (data:context) = function
		| Namespace_ast.AUnaryExpr expr -> 
			let data, expr = transform_unaryExpression (data:context) expr in
			data, (AUnaryExpr expr)
		| Namespace_ast.ABinaryExpr (op, expr1, expr2) ->
			let data, expr1 = transform_binaryExpression (data:context) expr1 in
			let data, expr2 = transform_binaryExpression (data:context) expr2 in
			data, (ABinaryExpr (op, expr1, expr2))

	and transform_conditionalExpression (data:context) = function
		| Namespace_ast.ACondBinaryExpr expr ->
			let data, expr = transform_binaryExpression (data:context) expr in
			data, (ACondBinaryExpr expr)
		| Namespace_ast.ACondTernaryExpr (expr1, expr2, expr3) ->
			let data, expr1 = transform_binaryExpression (data:context) expr1 in
			let data, expr2 = transform_assignmentExpression (data:context) expr2 in
			let data, expr3 = transform_assignmentExpression (data:context) expr3 in
			data, (ACondTernaryExpr (expr1, expr2, expr3))

	and transform_assignmentExpression (data:context) = function
		| Namespace_ast.ACondExpr expr -> 
			let data, expr = transform_conditionalExpression (data:context) expr in
			data, (ACondExpr expr)
		| Namespace_ast.AAssignOp (lhs,op,expr) ->
			let data, lhs = transform_leftHandSideExpression (data:context) lhs in
			let data, expr = transform_assignmentExpression (data:context) expr in
			data, (AAssignOp (lhs,op,expr))

	and transform_expression (data:context) exprs = 
		transform_list transform_assignmentExpression (data:context) exprs

	in
	transform_program ast

